Smart Pointer?

Same as C++ Smart,shared pointers, it allocates memory and deallocates when all references to it goes out of scope. They only point to 1 value. Examples: vec<T>, String.
Smart pointers are implemented using structs.

Interior mutability pattern

Interior mutability allows to mutate data even when there are immutable references to that data;
Normally, changing the data inside immutable reference is not allowed by Rust's borrowing rules.
But there are some cases eg(unsafe code) where we want to bend Rust’s usual rules.

Types of Smart Pointers

Box <T>

Boxes allow to store data on the heap rather than the stack. Pointer is data is stored on stack and actual data on heap.


fn main() {
    let b = Box::new(5);
    println!("b = {b}");
}
      

Rc<T> (Reference Counted Pointer) / Shared pointer

Multiple owners of 1 pointer. It keeps track of the number of references to a value to determine whether or not the value is still in use
If there are 0 references to a value, the value will be cleaned up
This is not thread safe by default
clone(): Invoking clone on Rc produces a new pointer to the same allocation in the heap.


use std::rc::Rc;
struct Person {
    name: String,
    age: u8,
}
fn main() {
    let person = Rc::new(Person {
        name: String::from("Alice"),
        age: 25,
    });

    println!("Name: {}", person.name);              //Alice
    println!("Age: {}", person.age);                //25

    let person_clone1 = person.clone();
    let person_clone2 = person.clone();

    println!("Number of owners: {}", Rc::strong_count(&person));  //3

    drop(person_clone2);
    println!("Number of owners: {}", Rc::strong_count(&person)); //2

    drop(person_clone1);
    println!("Number of owners: {}", Rc::strong_count(&person)); //1
}                
            

Features

1. Mutable Reference
Shared references in Rust disallow mutation by default. You cannot obtain a mutable reference to something inside an Rc
If you need mutability, put a Cell or RefCell inside the Rc

2. Thread Safe (No) Reference counting done by Rc is non-atomic, Hence overhead is less(wrt Arc<T> )
Rc does not implement Send Trait
Rust compiler will check at compile time that you are not sending Rcs between threads.

RefCell

It allows to implement interior mutability pattern, allowing to mutate data even we have an immutable reference
The Rule:
  Rust enforces its borrowing rules at compile time: we can have either 1 mutable reference (&mut T) or any number of immutable references (&T), but not both at the same time & this is checked at compile time
  With RefCell we move these borrowing checks from compile time to runtime. runtime. It tracks borrows dynamically using an internal counter. If you break the rules at runtime (e.g., trying to create two mutable borrows at once), your program will panic and crash instead of failing to compile